using Gurux.DLMS;
using Gurux.DLMS.ASN;
using Gurux.DLMS.Ecdsa;
using Gurux.DLMS.Enums;
using Gurux.DLMS.Objects.Enums;
using Gurux.DLMS.UI.Ecdsa;
using System;
using System.Collections.Generic;
using System.IO;
using System.Numerics;

namespace GXDLMSDirector
{
    public class DLMSTranslator
    {
        private GXCipheringSettings Ciphering;
        private GXDLMSTranslator translator;

        public DLMSTranslator()
        {
            
            translator = new GXDLMSTranslator(TranslatorOutputType.SimpleXml);

            translator.OnKeys += Translator_OnKeys;
            translator.Comments = true;

            translator.SecuritySuite = (SecuritySuite)Properties.Settings.Default.SecuritySuite;
            translator.Security = (Security)Enum.Parse(typeof(Security), Properties.Settings.Default.Security);
            translator.SystemTitle = GXDLMSTranslator.HexToBytes(Properties.Settings.Default.NotifySystemTitle);
            translator.ServerSystemTitle = GXDLMSTranslator.HexToBytes(Properties.Settings.Default.ServerSystemTitle);
            translator.BlockCipherKey = GXDLMSTranslator.HexToBytes(Properties.Settings.Default.NotifyBlockCipherKey);
            translator.AuthenticationKey = GXDLMSTranslator.HexToBytes(Properties.Settings.Default.AuthenticationKey);
            translator.InvocationCounter = (UInt32)Properties.Settings.Default.InvocationCounter;
            translator.DedicatedKey = GXDLMSTranslator.HexToBytes(Properties.Settings.Default.DedicatedKey);


            string certificates = null, keys = null;
            try
            {
                string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Virtual Module");
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
                certificates = Path.Combine(path, "Certificates");
                if (!Directory.Exists(certificates))
                {
                    Directory.CreateDirectory(certificates);
                }
                keys = Path.Combine(path, "Keys");
                if (!Directory.Exists(keys))
                {
                    Directory.CreateDirectory(keys);
                }
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message);
            }

            Ciphering = new GXCipheringSettings(translator, keys, certificates,
                  Properties.Settings.Default.ClientAgreementKey,
                  Properties.Settings.Default.ClientSigningKey,
                  Properties.Settings.Default.ServerAgreementKey,
                  Properties.Settings.Default.ServerSigningKey);
            Ciphering.Challenge = GXDLMSTranslator.HexToBytes(Properties.Settings.Default.Challenge);
            

        }

        /// <summary>
        /// Find correct key.
        /// </summary>
        private void Translator_OnKeys(object sender, GXCryptoKeyParameter args)
        {
            if (args.Encrypt)
            {
                //Private key is used when data is encrypted.
                args.PrivateKey = Ciphering.FindPrivateKey(args.SecuritySuite, args.CertificateType, args.SystemTitle);
            }
            else
            {
                //Public key is used for data decrypt.
                args.PublicKey = Ciphering.FindPublicKey(args.SecuritySuite, args.CertificateType, args.SystemTitle);
            }
        }

        private KeyValuePair<GXPkcs8, GXx509Certificate> FindKey(string SerialNumber)
        {
            BigInteger value = BigInteger.Parse(SerialNumber);
            foreach (var it in Ciphering.KeyPairs)
            {
                if (it.Value.SerialNumber == value)
                {
                    return it;
                }
            }
            return new KeyValuePair<GXPkcs8, GXx509Certificate>();
        }
        private void UpdateSecuritySettings()
        {
            translator.SecuritySuite = Ciphering.SecuritySuite;
            translator.Security = Ciphering.Security;
            translator.SystemTitle = Ciphering.SystemTitle;
            translator.ServerSystemTitle = Ciphering.ServerSystemTitle;
            translator.BlockCipherKey = Ciphering.BlockCipherKey;
            translator.AuthenticationKey = Ciphering.AuthenticationKey;
            translator.InvocationCounter = Ciphering.InvocationCounter;
            translator.DedicatedKey = Ciphering.DedicatedKey;
            translator.Keys.Clear();
            translator.Keys.AddRange(Ciphering.KeyPairs);
            if (!string.IsNullOrEmpty(Ciphering.ClientSigningKey))
            {
                KeyValuePair<GXPkcs8, GXx509Certificate> it = FindKey(Ciphering.ClientSigningKey);
                GXPrivateKey pk = null;
                if (it.Key != null)
                {
                    pk = it.Key.PrivateKey;
                    pk.SystemTitle = it.Value != null ? GXAsn1Converter.SystemTitleFromSubject(it.Value.Subject) : null;
                }
                translator.SigningKeyPair = new KeyValuePair<GXPublicKey, GXPrivateKey>(translator.SigningKeyPair.Key, pk);
            }
            if (!string.IsNullOrEmpty(Ciphering.ServerSigningKey))
            {
                KeyValuePair<GXPkcs8, GXx509Certificate> it = FindKey(Ciphering.ServerSigningKey);
                GXPublicKey pub = null;
                if (it.Value != null)
                {
                    pub = it.Value.PublicKey;
                    pub.SystemTitle = it.Value != null ? GXAsn1Converter.SystemTitleFromSubject(it.Value.Subject) : null;
                }
                translator.SigningKeyPair = new KeyValuePair<GXPublicKey, GXPrivateKey>(pub, translator.SigningKeyPair.Value);
            }
        }


        public string DlmsTranslator(string inContent)
        {
            UpdateSecuritySettings();
            GXByteBuffer bb = new GXByteBuffer();
            bb.Set(GXDLMSTranslator.HexToBytes(inContent));
            try
            {
                translator.Clear();
                translator.PduOnly = false;
                GXDLMSTranslatorMessage msg = new GXDLMSTranslatorMessage();
                msg.Message = bb;
                if (bb.Data[0] == 0x7E)
                {
                    msg.InterfaceType = Gurux.DLMS.Enums.InterfaceType.HDLC;
                }
                else
                {
                    msg.InterfaceType = Gurux.DLMS.Enums.InterfaceType.WRAPPER;
                }
                translator.MessageToXml(msg);
                return (msg.Xml);
            }
            catch (Exception ex)
            {
                return ("Translator Fail" + ex.Message);
            }
        }
        

    }
}